<?php

namespace WebmanGrpc;

use Google\Protobuf\Internal\Message;
use Grpc\ServerContext;

/**
 * gRPC服务基类
 * 
 * 所有gRPC服务都应继承此类，提供：
 * - 基础服务功能
 * - 拦截器支持
 * - 请求/响应处理
 * - 错误处理
 */
abstract class BaseService
{
    /**
     * 服务名称
     */
    protected string $serviceName;
    
    /**
     * 构造函数
     */
    public function __construct()
    {
        // 获取服务名称
        $this->serviceName = $this->getServiceName();
    }
    
    /**
     * 获取服务名称
     * 
     * 子类可以重写此方法返回服务名称
     * 
     * @return string 服务名称
     */
    protected function getServiceName(): string
    {
        return static::class;
    }
    
    /**
     * 处理gRPC请求
     * 
     * @param string $method 方法名
     * @param Message $request 请求消息
     * @param ServerContext $context 服务器上下文
     * @return Message 响应消息
     */
    public function handleRequest(string $method, Message $request, ServerContext $context): Message
    {
        // 获取拦截器
        $interceptors = Grpc::getInterceptors();
        
        // 创建处理链
        $handler = function (Message $request, ServerContext $context) use ($method) {
            return $this->callMethod($method, $request, $context);
        };
        
        // 应用拦截器
        foreach ($interceptors as $interceptorClass) {
            $interceptor = new $interceptorClass();
            $handler = function (Message $request, ServerContext $context) use ($interceptor, $handler) {
                return $interceptor->intercept($request, $context, $handler);
            };
        }
        
        // 执行处理链
        return $handler($request, $context);
    }
    
    /**
     * 调用具体方法
     * 
     * @param string $method 方法名
     * @param Message $request 请求消息
     * @param ServerContext $context 服务器上下文
     * @return Message 响应消息
     */
    protected function callMethod(string $method, Message $request, ServerContext $context): Message
    {
        // 检查方法是否存在
        if (!method_exists($this, $method)) {
            throw new \RuntimeException("Method {$method} not found in service {$this->serviceName}");
        }
        
        try {
            // 调用方法
            $response = $this->$method($request);
            
            // 验证响应
            if (!($response instanceof Message)) {
                throw new \RuntimeException("Method {$method} must return a Message instance");
            }
            
            return $response;
        } catch (\Throwable $e) {
            // 处理异常
            $this->handleException($e, $context);
            throw $e;
        }
    }
    
    /**
     * 处理异常
     * 
     * @param \Throwable $e 异常
     * @param ServerContext $context 服务器上下文
     * @return void
     */
    protected function handleException(\Throwable $e, ServerContext $context): void
    {
        // 记录错误日志
        echo "Error in service {$this->serviceName}: " . $e->getMessage() . "\n";
        
        // 设置状态码
        $status = new \Grpc\Status();
        $status->code = \Grpc\STATUS_INTERNAL;
        $status->details = $e->getMessage();
        
        $context->setStatus($status);
    }
    
    /**
     * 处理流式响应
     * 
     * @param \Generator $generator 生成器
     * @param ServerContext $context 服务器上下文
     * @return void
     */
    protected function handleStreamResponse(\Generator $generator, ServerContext $context): void
    {
        foreach ($generator as $response) {
            if (!($response instanceof Message)) {
                throw new \RuntimeException("Stream response must be a Message instance");
            }
            
            // 发送响应
            $context->write($response);
        }
    }
}